// 07_structs_and_methods.rs
// 演示 Rust 中的结构体（struct）和方法

// 1. 定义结构体
// 结构体是一种自定义数据类型，允许我们将多个相关的值组合在一起
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

// 2. 定义元组结构体
// 元组结构体有结构体名称但字段没有名称
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

// 3. 定义空结构体
// 空结构体没有任何字段，但在某些场景下仍有用处
struct AlwaysEqual;

// 4. 定义带有方法的结构体
struct Rectangle {
    width: u32,
    height: u32,
}

// 为 Rectangle 实现方法
impl Rectangle {
    // 方法的第一个参数总是 self，表示调用该方法的结构体实例
    fn area(&self) -> u32 {
        self.width * self.height
    }
    
    // 方法可以有多个参数
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
    
    // 关联函数（ Associated Functions ）
    // 不接收 self 作为参数，可以看作是结构体的静态方法
    fn square(size: u32) -> Rectangle {
        Rectangle {
            width: size,
            height: size,
        }
    }
}

// 可以有多个 impl 块
impl Rectangle {
    // 在第二个 impl 块中添加更多方法
    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }
}

// 5. 更复杂的结构体示例
struct Person {
    name: String,
    age: u8,
    address: Option<String>,
}

impl Person {
    // 构造函数（Rust 没有内置的构造函数）
    fn new(name: String, age: u8) -> Person {
        Person {
            name,
            age,
            address: None,
        }
    }
    
    // 设置地址
    fn set_address(&mut self, address: String) {
        self.address = Some(address);
    }
    
    // 获取格式化的信息
    fn get_info(&self) -> String {
        match &self.address {
            Some(addr) => format!("Name: {}, Age: {}, Address: {}", self.name, self.age, addr),
            None => format!("Name: {}, Age: {}, Address: Not provided", self.name, self.age),
        }
    }
}

// 将原来的 main 函数改为公共的 run 函数
pub fn run() {
    // 6. 创建结构体实例
    let user1 = User {
        email: String::from("someone@example.com"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };
    
    // 访问结构体字段
    println!("用户名: {}", user1.username);
    println!("电子邮件: {}", user1.email);
    
    // 7. 创建可变的结构体实例
    let mut user2 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername456"),
        active: true,
        sign_in_count: 1,
    };
    
    // 修改可变结构体的字段
    user2.email = String::from("updated_email@example.com");
    user2.sign_in_count += 1;
    
    println!("\n更新后的电子邮件: {}", user2.email);
    println!("登录次数: {}", user2.sign_in_count);
    
    // 8. 从其他实例创建新实例（结构体更新语法）
    let user3 = User {
        email: String::from("third@example.com"),
        username: String::from("thirdusername789"),
        // .. 语法表示其余字段从 user2 复制
        ..user2
    };
    
    println!("\nuser3 用户名: {}", user3.username);
    println!("user3 登录次数: {}", user3.sign_in_count);
    
    // 注意：由于 String 没有实现 Copy trait，user2 的 email 和 username 字段被移动到 user3
    // 所以 user2 现在只能访问 active 和 sign_in_count 字段
    // println!("user2 用户名: {}", user2.username); // 这会导致编译错误
    
    // 9. 使用元组结构体
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
    
    // 访问元组结构体的字段
    println!("\n黑色 RGB 值: {}, {}, {}", black.0, black.1, black.2);
    println!("原点坐标: ({}, {}, {})", origin.0, origin.1, origin.2);
    
    // 10. 使用空结构体
    let subject = AlwaysEqual;
    
    // 11. 使用带有方法的结构体
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    
    // 调用方法
    println!("\n矩形面积: {}", rect1.area());
    println!("矩形周长: {}", rect1.perimeter());
    
    let rect2 = Rectangle {
        width: 20,
        height: 40,
    };
    
    // 调用带参数的方法
    println!("rect1 能包含 rect2: {}", rect1.can_hold(&rect2));
    println!("rect2 能包含 rect1: {}", rect2.can_hold(&rect1));
    
    // 12. 调用关联函数（使用 :: 语法）
    let square = Rectangle::square(30);
    println!("\n正方形面积: {}", square.area());
    println!("正方形周长: {}", square.perimeter());
    
    // 13. 使用 Person 结构体及其方法
    let mut person = Person::new(String::from("张三"), 30);
    println!("\n{}", person.get_info());
    
    person.set_address(String::from("北京市朝阳区"));
    println!("更新地址后:\n{}", person.get_info());
    
    // 14. 结构体所有权示例
    let user4 = build_user(
        String::from("newuser@example.com"), 
        String::from("newuser")
    );
    
    println!("\n新用户信息:");
    println!("用户名: {}", user4.username);
    println!("电子邮件: {}", user4.email);
} // main 函数结束

// 15. 结构体作为函数参数和返回值
fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}